#if !defined(_AVALUE_H_)
#define _AVALUE_H_

#include "AObject.h"

typedef enum enumSettingValueType
{
	SVT_Unknown,
	SVT_Float,
	SVT_String,
	SVT_Point,
	SVT_Size,
	SVT_Rect,
	SVT_Bool,
	SVT_Integer,
}
ESettingValueType;

class CAValueObject : public CAObject
{
protected:
	ESettingValueType _type;
	void* _value;

	void _clear()
	{
		switch(_type)
		{
		case SVT_Unknown:
			break;
		case SVT_String:
			delete (CAString*)_value;
			break;
		case SVT_Point:
			delete (CCPoint*)_value;
			break;
		case SVT_Size:
			delete (CCSize*)_value;
			break;
		case SVT_Rect:
			delete (CCRect*)_value;
			break;
		case SVT_Float:
		case SVT_Bool:
		case SVT_Integer:
			break;
		default:
			_Assert(false);
		}
		_type = SVT_Unknown;
		_value = null;
	}
	
	template<class _T>
	void _setValue(ESettingValueType t, const _T& v)
	{
		GUARD_FUNCTION();

		_clear();
		_type = t;
		if (t == SVT_Bool ||
			t == SVT_Float ||
			t == SVT_Integer ||
			0)
		{
			*((_T*)(&_value)) = v;
		}
		else
		{
			_value = new _T;
			*(_T*)_value = v;
		}
	}
	template<class _T>
	_T _getValue(ESettingValueType t) const
	{
		_Assert(_type == t);
		if (t == SVT_Bool ||
			t == SVT_Float ||
			t == SVT_Integer ||
			0)
		{
			return *((_T*)(&_value));
		}
		else
		{
			return *(_T*)_value;
		}
	}
public:
	CAValueObject()
	{
		_type = SVT_Unknown;
		_value = null;
		autorelease();
	}
	virtual ~CAValueObject()
	{
		_clear();
	}

	ESettingValueType getType() const { return _type; }

#define SET_FUNC(name, IT, T) \
	inline void set##name(IT v) { _setValue<T>(SVT_##name, v); }

	SET_FUNC(Float, float, float);
	SET_FUNC(Integer, int, int);
	SET_FUNC(Bool, bool, bool);
	SET_FUNC(String, const CAString&, CAString);
	SET_FUNC(Point, const CCPoint&, CCPoint);
	SET_FUNC(Size, const CCSize&, CCSize);
	SET_FUNC(Rect, const CCRect&, CCRect);
#undef SET_FUNC
#define GET_FUNC(name, T) \
	inline T get##name() const { return _getValue<T>(SVT_##name); }
	
	GET_FUNC(Float, float);
	GET_FUNC(Integer, int);
	GET_FUNC(Bool, bool);
	GET_FUNC(String, CAString);
	GET_FUNC(Point, CCPoint);
	GET_FUNC(Size, CCSize);
	GET_FUNC(Rect, CCRect);
#undef GET_FUNC
};

class CAValueChangedListener
{
public:
	virtual void onValueChanged(CAValueObject* pv) = 0;
};

class CAValues : public CAStringMap<CAValueObject>
{
protected:
	CAValueChangedListener* _listener;
public:
	CAValues() { _listener = null; };
	virtual ~CAValues() {};

	void setListener(CAValueChangedListener* pl) { _listener = pl; }

	inline bool hasKey(const char* name)
	{
		return null != this->objectForKey(name);
	}

	inline CAValueObject* getValue(const char* name)
	{
		return (CAValueObject*)this->objectForKey(name);
	}
#define DEF_GET_XXX(type, name, dv) \
	inline type get##name(const char* key, type def = dv) \
	{ \
		CAValueObject* pvo = (CAValueObject*)this->objectForKey(key); \
		if (null == pvo) return def; \
		else return pvo->get##name(); \
	}

	DEF_GET_XXX(float, Float, 0.0f);
	DEF_GET_XXX(int, Integer, 0);
	DEF_GET_XXX(bool, Bool, false);
	DEF_GET_XXX(CAString, String, "");
	DEF_GET_XXX(CCPoint, Point, CCPointZero);
	DEF_GET_XXX(CCSize, Size, CCSizeZero);
	DEF_GET_XXX(CCRect, Rect, CCRectZero);

#undef DEF_GET_XXX

#define DEF_SET_XXX(type, name) \
	inline void set##name(const char* key, type v) \
	{ \
		GUARD_FUNCTION(); \
		CAValueObject* pv = (CAValueObject*)this->objectForKey(key); \
		if (null == pv) \
		{ \
			pv = new CAValueObject(); \
			this->setObject(pv, key); \
		}\
		pv->set##name(v); \
		if (_listener) _listener->onValueChanged(pv); \
	}

	DEF_SET_XXX(float, Float);
	DEF_SET_XXX(int, Integer);
	DEF_SET_XXX(bool, Bool);
	DEF_SET_XXX(const CAString&, String);
	DEF_SET_XXX(const CCPoint&, Point);
	DEF_SET_XXX(const CCSize&, Size);
	DEF_SET_XXX(const CCRect&, Rect);

#undef DEF_SET_XXX
};

#endif //_AVALUE_H_
